﻿using System;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.Web;
using SecurityClient;

namespace SecurityModule.Workflows
{
    class WFPostAppAccountChangePassword : SimpleWorkflow
    {
        public WFPostAppAccountChangePassword()
        {
            Verb = "POST";
            Path = "/App/Account/ChangePassword";
        }
        public override void PreProcessImplementation(HttpContext context)
        {
            // verify token, activate and add Email and ClientCode to Request.Form
            var callback = new Func<string, string>(formFields =>
                {
                    var fields = HttpUtility.ParseQueryString(formFields);

                    //Read fields
                    var email = fields["Email"];
                    var currentPassword = fields["CurrentPassword"];
                    var password = fields["NewPassword"];
                    var password2 = fields["NewPassword2"];

                    //Whitelist the following fields to prevent password from being sidebanded.
                    string[] whitelistFields = { "Email", "CurrentPassword", "NewPassword", "NewPassword2" };
                    foreach (var key in fields.AllKeys.Where(key => !whitelistFields.Contains(key)))
                    {
                        fields.Remove(key);
                    }

                    var hasErrors = false;
                    if (string.IsNullOrEmpty(password))
                    {
                        fields.Add("EXTERR_Password", "Please provide a password");
                        hasErrors = true;
                    }
                    if (string.IsNullOrEmpty(password2))
                    {
                        fields.Add("EXTERR_Password2", "Please confirm your password");
                        hasErrors = true;
                    }
                    if (!hasErrors && !password.Equals(password2))
                    {
                        fields.Add("EXTERR_Password2", "Passwords don't match");
                        hasErrors = true;
                    }
                    if (hasErrors)
                    {
                        return fields.ToString();
                    }

                    try
                    {
                        var security = new SecurityServiceProxy();
                        var result = security.ChangePassword(email, currentPassword, password);
                        if (result.Success)
                        {
                            //Inject password into app
                            fields["CurrentPassword"] = result.OldPassword;
                            fields["NewPassword"] = result.NewPassword;
                            fields["NewPassword2"] = result.NewPassword;
                            //Store transactionId for later commit.
                            context.Items["TransactionId"] = result.TransactionId;
                        }
                        else
                        {
                            //Inject password into app
                            fields["CurrentPassword"] = "error";
                            fields["NewPassword"] = "error";
                            fields["NewPassword2"] = "error";

                            //Bubble up an error to the application
                            fields.Add("EXTERRMSG", result.ErrorMessage);
                        }
                    }
                    catch (Exception exception)
                    {
                        if (exception is PipeException || exception is EndpointNotFoundException)
                        {
                            //If the security service is offline or broken
                            if (fields.AllKeys.Contains("EXTERRMSG"))
                            {
                                fields["EXTERRMSG"] = SecurityServiceDownMsg;
                            }
                            else
                            {
                                fields.Add("EXTERRMSG", SecurityServiceDownMsg);
                            }
                        }
                        else
                        {
                            if (fields.AllKeys.Contains("EXTERRMSG"))
                            {
                                fields["EXTERRMSG"] = exception.Message;
                            }
                            else
                            {
                                fields.Add("EXTERRMSG", exception.Message);
                            }
                        }
                    }
                    return fields.ToString();
                });
            context.Request.Filter = new RequestFilter(context.Request.Filter, context.Request.ContentEncoding, callback);
        }

        public override void PostProcessImplementation(HttpContext context)
        {
            if (context.Response.StatusCode != 200 && context.Response.StatusCode != 302) return;
            var transactionId = context.Items["TransactionId"];
            if (transactionId == null) return;
            try
            {
                var security = new SecurityServiceProxy();
                security.Commit((Guid)transactionId);
            }
            // ReSharper disable EmptyGeneralCatchClause
            catch (Exception)
            {
                //If the security service is offline or broken then swallow the exception
            }
            // ReSharper restore EmptyGeneralCatchClause
        }
    }
}
